using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using ElteIk.RoboSoccer.Core;
using ElteIk.RoboSoccer.Core.Physics;

namespace ElteIk.RoboSoccer.Graphics
{
	/// <summary>
	/// A rendering engine using standard GDI+ methods available in .NET 2.0. 
	/// This class is mainly for testing and Mono compatibility.
	/// </summary>
	public class GdiGraphicsEngine : RoboSoccer.Graphics.GraphicsEngine
	{
		private Control renderSurface;
		
		//private System.Threading.Timer timer;
		//private object timerState = new int();

        private RobotPlayer selectedRobot = null;

		private System.Drawing.Graphics targetGraphics;

		public GdiGraphicsEngine(SoccerGame game, Control renderSurfaceControl)
			: base(game)
		{
			if (renderSurfaceControl == null)
			{
				throw new ArgumentNullException("renderSurfaceControl", "You must provide a valid Windows.Forms.Control instance to render on.");
			}

			renderSurface = renderSurfaceControl;
			game.Updated += new EventHandler(delegate(object sender, EventArgs e) { Update(); });

			renderSurface.Paint += delegate(object sender, PaintEventArgs e)
			{
				targetGraphics = e.Graphics;
				float totalFieldWidth = game.Field.Width + 2 * game.Field.WallThickness;
				float totalFieldHeight = game.Field.Height + 2 * game.Field.WallThickness;

				float widthRatio = (float)renderSurface.Width / totalFieldWidth;
				float heightRatio = (float)renderSurface.Height / totalFieldHeight;

				float ratio = Math.Min(widthRatio, heightRatio);

                float widthDifference = renderSurface.Width - ratio * totalFieldWidth;

                targetGraphics.TranslateTransform(widthDifference / 2, 0f);
				targetGraphics.ScaleTransform(ratio, ratio);
				Render();
			};

			// Initialize periodical refreshing
			// timer = new System.Threading.Timer(new System.Threading.TimerCallback(RefresherMethod), timerState, 100, 25);
		}

		/// <summary>
		/// Rerenders the scene.
		/// </summary>
		public override void Update()
		{
			RefresherMethod(null);
		}

		/// <summary>
		/// Forces the Control to redraw itself and raise the Paint event that we will catch.
		/// </summary>
		/// <param name="state"></param>
		private void RefresherMethod(object state)
		{
			renderSurface.Invalidate();
		}

		/// <summary>
		/// Renders the scene.
		/// </summary>
		protected void Render()
		{
			if (game.Ball != null)
			{
				DrawBall(game.Ball);
			}
			DrawField(game.Field);
			foreach (IPlayer player in game.Players)
			{
				if (player is Polygon)
					DrawPolygon(player as Polygon);
			}
		}

		/// <summary>
		/// Draws the soccerfield.
		/// </summary>
		/// <param name="graphics"></param>
		/// <param name="soccerField"></param>
		protected override void DrawField(SoccerField soccerField)
		{
			foreach (IPhysicalObject physicalObject in soccerField.Objects)
			{
				if (physicalObject is Polygon)
				{
					DrawPolygon(physicalObject as Polygon);
				}
			}
		}

		/// <summary>
		/// Draws a general polygon. Walls, goals and roboplayers are polygons.
		/// </summary>
		/// <param name="graphics"></param>
		/// <param name="polygon"></param>
        protected override void DrawPolygon(Polygon polygon)
        {
			System.Drawing.Pen pen = System.Drawing.Pens.Black;

			if (polygon is RobotPlayer)
			{
				RobotPlayer robot = (RobotPlayer)polygon;
				if (robot.Team.Id == 0)
				{
					pen = System.Drawing.Pens.Blue;
				}
				else
				{
					pen = System.Drawing.Pens.Red;
				}
			}

			if (polygon is RobotPlayer && polygon == selectedRobot)
			{
				pen = System.Drawing.Pens.Green;
			}

			targetGraphics.TranslateTransform(polygon.Position.X, polygon.Position.Y);
			targetGraphics.RotateTransform(polygon.Rotation);
            System.Drawing.Point[] points = new System.Drawing.Point[polygon.Points.Count];
            for (int i = 0; i < polygon.Points.Count; ++i)
            {
                points[i] = new System.Drawing.Point((int)polygon.Points[i].X, (int)polygon.Points[i].Y);
            }

            targetGraphics.DrawPolygon(pen, points);
			targetGraphics.FillEllipse(System.Drawing.Brushes.Blue, -0.5f, -0.5f, 1f, 1f);
			targetGraphics.RotateTransform(-polygon.Rotation);
			targetGraphics.TranslateTransform(-polygon.Position.X, -polygon.Position.Y);
        }

		/// <summary>
		/// Draws the ball.
		/// </summary>
		/// <param name="ball"></param>
		protected override void DrawBall(Ball ball)
		{
			targetGraphics.FillEllipse(System.Drawing.Brushes.Black, ball.Position.X - ball.Radius, ball.Position.Y - ball.Radius, ball.Radius * 2, ball.Radius * 2);
		}

        /// <summary>
        /// Sets the selected robot to be able to render it different color.
        /// </summary>
        /// <param name="robot"></param>
        public void SelectRobot(RobotPlayer robot)
        {
            selectedRobot = robot;
        }
    }
}
